using System;
using System.Collections.Generic;
using System.Text;
using System.ComponentModel;
using System.Reflection;

namespace Banshee.Controls
{
    /// <summary>
    /// This class represents a PropertyDescriptor for subproperties
    /// </summary>
    /// <typeparam name="T"></typeparam>
    public class SubPropertyDescriptor<T> : PropertyDescriptor
    {
        #region Fields

        private PropertyInfo propertyInfo;

        #endregion

        #region Constructors

        /// <summary>
        /// Constructor
        /// </summary>
        /// <param name="name"></param>
        public SubPropertyDescriptor(string name)
            : base(name, null)
        {
            Type t = typeof(T);
            this.propertyInfo = null;

            string[] subPropertyNames = name.Split('.');
            if (subPropertyNames.Length == 1)
            {
                // a regular property
                this.propertyInfo = t.GetProperty(name);
            }
            else
            {
                // navigate through the subproperties
                for (int i = 0; i < subPropertyNames.Length; ++i)
                {
                    this.propertyInfo = t.GetProperty(subPropertyNames[i]);
                    t = this.propertyInfo.PropertyType;
                }
            }
        }

        #endregion

        #region Overriden Methods

        /// <summary>
        /// <see cref="PropertyDescriptor.ComponentType"/>
        /// </summary>
        public override Type ComponentType
        {
            get { return typeof(T); }
        }

        /// <summary>
        /// <see cref="PropertyDescriptor.PropertyType"/>
        /// </summary>
        public override Type PropertyType
        {
            get { return this.propertyInfo.PropertyType; }
        }

        /// <summary>
        /// <see cref="PropertyDescriptor.IsReadOnly"/>
        /// </summary>
        public override bool IsReadOnly
        {
            get { return false; }
        }

        /// <summary>
        /// <see cref="PropertyDescriptor.GetValue"/>
        /// </summary>
        public override object GetValue(object component)
        {
            object value = component;
            foreach (string property in this.Name.Split('.'))
            {
                value = value.GetType().GetProperty(property).GetValue(value, null);
            }

            return value;
        }

        /// <summary>
        /// <see cref="PropertyDescriptor.SetValue"/>
        /// </summary>
        public override void SetValue(object component, object value)
        {
            Type t = typeof(T);
            PropertyInfo subPropertyInfo = null;

            string[] subPropertyNames = this.Name.Split('.');
            if (subPropertyNames.Length == 1)
            {
                // a regular property
                subPropertyInfo = t.GetProperty(this.Name);
            }
            else
            {
                // navigate through the subproperties
                for (int i = 0; i < subPropertyNames.Length; ++i)
                {
                    subPropertyInfo = t.GetProperty(subPropertyNames[i]);
                    t = subPropertyInfo.PropertyType;

                    if (i < subPropertyNames.Length - 1)
                    {
                        component = subPropertyInfo.GetValue(component, null);
                    }
                }
            }

            subPropertyInfo.SetValue(component, value, null);
        }

        /// <summary>
        /// <see cref="PropertyDescriptor.CanResetValue"/>
        /// </summary>
        public override bool CanResetValue(object component)
        {
            return false;
        }

        /// <summary>
        /// <see cref="PropertyDescriptor.ResetValue"/>
        /// </summary>
        public override void ResetValue(object component)
        {
        }

        /// <summary>
        /// <see cref="PropertyDescriptor.ShouldSerializeValue"/>
        /// </summary>
        public override bool ShouldSerializeValue(object component)
        {
            return false;
        }

        #endregion
    }
}
